#include "../Buffer/Buffers.hpp"
#include "../Buffer/VertexBuffer.hpp"
#include "MeshRenderer.hpp"

using namespace Model;
using namespace Program;

namespace Renderer {

MeshRenderer::MeshRenderer(const MeshBuffer &buffer)
    : _id{0}, _buffer{buffer}, _material() {
  Init();
}

MeshRenderer::~MeshRenderer() {
  if (_id) {
    glDeleteVertexArrays(1, &_id);
  }
}

void MeshRenderer::Init() {
  glCreateVertexArrays(1, &_id);
  // TODO: 实现接下来的初始化操作
  // Specify Attribute format
  size_t stride = 0;
  auto formats = _buffer.GetMesh()->GetFormat();
  std::vector<GLuint> attribIndex;
  for (size_t i = 0; i < formats.size(); i++) {
    auto comp = GetAttribTypeComp(formats.at(i).type);
    glEnableVertexArrayAttrib(_id, i);
    glVertexArrayAttribFormat(_id, i, comp, GetGLType(formats.at(i).dataType), GL_FALSE,
                              formats.at(i).offset *
                                  GetDataBytes(formats.at(i).dataType));
    glVertexArrayAttribBinding(_id, i, 0);
    stride += comp;
    attribIndex.push_back(i);
  }
  glVertexArrayVertexBuffer(_id, 0, _buffer.GetBuffer()->GetID(), (GLintptr)0,
                            GLsizei(stride * sizeof(float)));
  _material.GetProgram()->BindAttributes(_buffer.GetMesh()->GetFormat());
  _material.Apply();
  Program::CheckActiveAttributes(_material.GetProgram()->GetID(), attribIndex);
}

void MeshRenderer::Draw() {
  BeforeDraw();
  glDrawArrays(GL_TRIANGLES, 0, _buffer.GetMesh()->GetVertCount());
  EndDraw();
}

void MeshRenderer::BeforeDraw() {
  glBindVertexArray(_id);
  _material.UpdateProperties();
}

void MeshRenderer::EndDraw() {
  _material.GetProgram()->UnUse();
  glBindVertexArray(0);
}
} // namespace Renderer